package com.sinsz.pay.factory;

import com.sinsz.common.Result;
import com.sinsz.pay.dto.*;
import com.sinsz.pay.factory.support.BillType;
import org.nutz.json.Json;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.ResponseEntity;

import java.util.Date;

/**
 * 支付公共处理接口
 *
 * @author chenjianbo
 */
public interface Pay {

    /**
     * 统一下单，预支付创建
     * @param outTradeNo    自定义商户订单号
     * @param body          主描述信息
     * @param detail        描述信息
     * @param fee           费用，精度：分
     * @param openid        公众号时为公众号唯一的用户ID
     * @return              支付串
     */
    String unifiedOrder(String outTradeNo, String body, String detail, int fee, String openid);

    /**
     * 统一下单，预支付创建
     * @param outTradeNo    自定义商户订单号
     * @param body          主描述信息
     * @param detail        描述信息
     * @param fee           费用，精度：分
     * @param openid        公众号时为公众号唯一的用户ID
     * @return              支付串
     */
    default Result<String> unifiedOrderResult(String outTradeNo, String body, String detail, int fee, String openid) {
        return Result.ok(unifiedOrder(outTradeNo, body, detail, fee, openid));
    }

    /**
     * 查询订单
     * @param transactionId     支付平台的订单号
     * @param outTradeNo        自定义商户订单号
     * @return                  支付结果
     */
    String orderQuery(String transactionId, String outTradeNo);

    /**
     * 查询订单
     * @param transactionId     支付平台的订单号
     * @param outTradeNo        自定义商户订单号
     * @return                  支付结果
     */
    default Result<OrderQueryDto> orderQueryResult(String transactionId, String outTradeNo) {
        return Result.ok(
                Json.fromJson(OrderQueryDto.class, orderQuery(transactionId, outTradeNo))
        );
    }

    /**
     * 关闭订单
     * @param outTradeNo        自定义的商户订单号
     * @return                  成功状态或错误信息
     */
    String closeOrder(String outTradeNo);

    /**
     * 关闭订单
     * @param outTradeNo        自定义的商户订单号
     * @return                  成功状态或错误信息
     */
    default Result<String> closeOrderResult(String outTradeNo) {
        return Result.ok(closeOrder(outTradeNo));
    }

    /**
     * 申请退款
     * <p>
     *     未入账(未结算)订单可退款，已入账订单建议使用人工客服方式退款。
     * </p>
     * @param transactionId     支付平台的订单号
     * @param outTradeNo        自定义商户订单号
     * @param outRefundNo       退款单号
     * @param totalFee          总金额/剩余退款
     * @param fee               退款金额
     * @param refundDesc        退款原因
     * @return                  退款信息
     */
    String refund(String transactionId, String outTradeNo, String outRefundNo, int totalFee, int fee, String refundDesc);

    /**
     * 申请退款
     * <p>
     *     未入账(未结算)订单可退款，已入账订单建议使用人工客服方式退款。
     * </p>
     * @param transactionId     支付平台的订单号
     * @param outTradeNo        自定义商户订单号
     * @param outRefundNo       退款单号
     * @param totalFee          总金额/剩余退款
     * @param fee               退款金额
     * @param refundDesc        退款原因
     * @return                  退款信息
     */
    default Result<RefundDto> refundResult(String transactionId, String outTradeNo, String outRefundNo, int totalFee, int fee, String refundDesc) {
        return Result.ok(
                Json.fromJson(RefundDto.class, refund(transactionId, outTradeNo, outRefundNo, totalFee, fee, refundDesc))
        );
    }

    /**
     * 退款查询
     * @param refundId          支付平台退款交易号
     *                          <p>
     *                              如果是支付宝平台：refundId则为outTradeNo
     *                          </p>
     * @param outRefundNo       自定义商户退款单号
     * @return                  退款结果
     */
    String refundQuery(String refundId, String outRefundNo);

    /**
     * 退款查询
     * @param refundId          支付平台退款交易号
     *                          <p>
     *                              如果是支付宝平台：refundId则为outTradeNo
     *                          </p>
     * @param outRefundNo       自定义商户退款单号
     * @return                  退款结果
     */
    default Result<RefundQueryDto> refundQueryResult(String refundId, String outRefundNo) {
        return Result.ok(
                Json.fromJson(RefundQueryDto.class, refundQuery(refundId, outRefundNo))
        );
    }

    /**
     * 下载对账单
     * @param date          对账日期
     * @param billType      对账类型
     * @return              文件流
     */
    ResponseEntity<InputStreamResource> downloadBill(Date date, BillType billType);

    /**
     * 支付结果通知
     * <p>
     *     由支付平台自动回执解析，
     *     用于回调接口中获取并解析回执参数对象
     * </p>
     * @return          结果
     */
    String payNotify();

    /**
     * 支付结果通知
     * <p>
     *     由支付平台自动回执解析，
     *     用于回调接口中获取并解析回执参数对象
     * </p>
     * @return          结果
     */
    default Result<String> payNotifyResult() {
        return Result.ok(payNotify());
    }

    /**
     * 退款结果通知
     * <p>
     *     由支付平台自动回执解析，
     *     用于回调接口中获取并解析回执参数对象
     *     微信支付用户暂时不建议使用该接口，如需要使用，需用户自行实现加密串解密
     * </p>
     * @return          结果
     */
    String refundNotify();

    /**
     * 退款结果通知
     * <p>
     *     由支付平台自动回执解析，
     *     用于回调接口中获取并解析回执参数对象
     *     微信支付用户暂时不建议使用该接口，如需要使用，需用户自行实现加密串解密
     * </p>
     * @return          结果
     */
    default Result<String> refundNotifyResult() {
        return Result.ok(refundNotify());
    }

    /**
     * 打款
     * <p>
     *     如果是微信(公众平台)，则主要实现付款到零钱
     * </p>
     * @param partnerTradeNo    商户自定义的打款单号
     * @param userName          用户真实姓名
     * @param amount            打款金额，精度：分
     * @param desc              打款描述
     * @param openid            微信打款到零钱时使用,支付宝平台是对应用户的收款账号
     * @return                  打款信息
     */
    String transfers(String partnerTradeNo,String userName, int amount, String desc, String openid);

    /**
     * 打款
     * <p>
     *     如果是微信(公众平台)，则主要实现付款到零钱
     * </p>
     * @param partnerTradeNo    商户自定义的打款单号
     * @param userName          用户真实姓名
     * @param amount            打款金额，精度：分
     * @param desc              打款描述
     * @param openid            微信打款到零钱时使用,支付宝平台是对应用户的收款账号
     * @return                  打款信息
     */
    default Result<TransferDto> transfersResult(String partnerTradeNo, String userName, int amount, String desc, String openid) {
        return Result.ok(
                Json.fromJson(TransferDto.class, transfers(partnerTradeNo, userName, amount, desc, openid))
        );
    }

    /**
     * 查询企业付款状态
     * <p>
     *     如果是微信(公众平台)，则主要实现付款到零钱查询
     * </p>
     * @param partnerTradeNo    商户自定义的打款单号
     * @return                  打款结果
     */
    String getTransferInfo(String partnerTradeNo);

    /**
     * 查询企业付款状态
     * <p>
     *     如果是微信(公众平台)，则主要实现付款到零钱查询
     * </p>
     * @param partnerTradeNo    商户自定义的打款单号
     * @return                  打款结果
     */
    default Result<TransferQueryDto> getTransferInfoResult(String partnerTradeNo) {
        return Result.ok(
                Json.fromJson(TransferQueryDto.class, getTransferInfo(partnerTradeNo))
        );
    }

}
